﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Infrastructure.Utility
{
    public static partial class Extensions
    {
        #region object extensions
        /// <summary>
        /// 
        /// </summary>
        /// <param name="o"></param>
        /// <returns></returns>
        public static string ToStringEx(this object o)
        {
            return Convert.ToString(o).Trim();
        }

        /// <summary>
        /// 将object安全转换成指定类型的对象. "2131".To<int>();
        /// </summary>
        /// <param name="obj">要转换的数据</param>
        /// <returns>结果</returns>
        public static T To<T>(this object obj)
        {
            if (obj == null || obj == DBNull.Value) return default(T);
            else if (obj.GetType().FullName == typeof(T).FullName) return (T)obj;
            return (T)obj.Cast(typeof(T));
        }
        /// <summary>
        /// 通用转换
        /// </summary>
        /// <param name="value"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static object Cast(this object value, Type type)
        {
            if (value == null && type.IsGenericType) return Activator.CreateInstance(type);
            if (value == null) return null;
            if (type == value.GetType()) return value;
            if (type.IsEnum)
            {
                if (value is string) return Enum.Parse(type, value as string);
                else return Enum.ToObject(type, value);
            }
            if (!type.IsInterface && type.IsGenericType)
            {
                Type innerType = type.GetGenericArguments()[0];
                object innerValue = Cast(value, innerType);
                return Activator.CreateInstance(type, new object[] { innerValue });
            }
            if (value is string && type == typeof(Guid)) return new Guid(value as string);
            if (value is string && type == typeof(Version)) return new Version(value as string);
            if (!(value is IConvertible)) return value;
            return Convert.ChangeType(value, type);
        }
        public static object Val(this object obj, string property, object val = null)
        {
            if (obj == null) return null;
            if (val != null)
            {
                obj.GetType().GetProperty(property).SetValue(obj, val, null);
                return val;
            }
            else
            {
                return obj.GetType().GetProperty(property).GetValue(obj, null);
            }
        }

        public static object Invoke(this object obj, string fn, params object[] args)
        {
            var f = obj.GetType().GetMethod(fn);
            if (f == null) return null;
            else return f.Invoke(obj, args);
        }
        #endregion

        #region datetime extensions

        public static string ToStandradString(this DateTime datetTime)
        {
            return datetTime.ToString("yyyy-MM-dd HH:mm:ss");
        }

        public static string ToDateString(this DateTime dateTime)
        {
            return dateTime.ToString("yyyy-MM-dd");
        }

        /// <summary>
        /// DateTime比较
        /// </summary>
        /// <param name="src">开始日期</param>
        /// <param name="target">结束日期</param>
        /// <param name="part">比较对象,不区分大小写(0-年   1-月   2-日   3-时   4-分   5-秒)</param>
        /// <returns></returns>
        public static double DtCompare(this DateTime src, DateTime target, int part)
        {
            if (part >= 2)
            {
                TimeSpan span = target - src;
                switch (part)
                {
                    case 2: return span.TotalDays;
                    case 3: return span.TotalHours;
                    case 4: return span.TotalMinutes;
                    default: return span.TotalSeconds;
                }
            }
            else if (part == 1)
            {
                return (target.Year - src.Year) * 12 + (target.Month - src.Month);
            }
            else if (part == 0)
            {
                return target.Year - src.Year;
            }

            return int.MinValue;
        }

        #endregion

        #region string extensions

        public static bool IsAvailable(this string s)
        {
            return !(string.IsNullOrEmpty(s) || s.Trim() == string.Empty);
        }
        public static bool IsNumber(this string s)
        {
            decimal d = 0;
            return decimal.TryParse(s, out d);
        }

        public static bool IsInteger(this string s)
        {
            int i = 0;
            return int.TryParse(s, out i);
        }

        public static DateTime ToDate(this string dateTimeString)
        {
            if (dateTimeString.Length > 10)
                dateTimeString = dateTimeString.Substring(0, 10);
            DateTime d;
            DateTime.TryParse(dateTimeString, out d);
            return d;
        }

        public static DateTime ToDataTime(this string datetime_14len)
        {
            DateTime d;
            if (datetime_14len != null)
            {
                datetime_14len = datetime_14len.Trim().Replace(":", "");
                if (datetime_14len.Length == 14 && (new System.Text.RegularExpressions.Regex("^[0-9]+$").IsMatch(datetime_14len)))
                {
                    string[] arrDateStr = new string[3];
                    string[] arrTimeStr = new string[3];
                    arrDateStr[0] = datetime_14len.Substring(0, 4);
                    arrDateStr[1] = datetime_14len.Substring(4, 2);
                    arrDateStr[2] = datetime_14len.Substring(6, 2);
                    arrTimeStr[0] = datetime_14len.Substring(8, 2);
                    arrTimeStr[1] = datetime_14len.Substring(10, 2);
                    arrTimeStr[2] = datetime_14len.Substring(12, 2);
                    if (DateTime.TryParse(string.Join("-", arrDateStr) + " " + string.Join(":", arrTimeStr), out d)) return d;
                }
            }
            throw new Exception("此字符串不是有效的时间格式字符串。");
        }

        public static string FormatDateTimeString(this string datetime_14len)
        {
            string datetime = string.Empty;
            if (datetime_14len != null)
            {
                datetime_14len = datetime_14len.Trim().Replace(":", "");
                if (datetime_14len.Length != 14 || (!(new System.Text.RegularExpressions.Regex("^[0-9]+$").IsMatch(datetime_14len.Trim())))) return datetime;
                string[] arrDateStr = new string[3];
                string[] arrTimeStr = new string[3];
                arrDateStr[0] = datetime_14len.Substring(0, 4);
                arrDateStr[1] = datetime_14len.Substring(4, 2);
                arrDateStr[2] = datetime_14len.Substring(6, 2);
                arrTimeStr[0] = datetime_14len.Substring(8, 2);
                arrTimeStr[1] = datetime_14len.Substring(10, 2);
                arrTimeStr[2] = datetime_14len.Substring(12, 2);
                datetime = string.Join("-", arrDateStr) + " " + string.Join(":", arrTimeStr);
                DateTime d;
                if (!DateTime.TryParse(datetime, out d)) datetime = string.Empty;
            }
            return datetime;
        }

        public static string FormatDateString(this string date_len8)
        {
            string datetime = string.Empty;
            if (date_len8 != null)
            {
                date_len8 = date_len8.Trim().Replace(":", "");
                if (date_len8.Length < 8 || (!(new System.Text.RegularExpressions.Regex("^[0-9]+$").IsMatch(date_len8)))) return datetime;
                string[] arrDateStr = new string[3];
                arrDateStr[0] = date_len8.Substring(0, 4);
                arrDateStr[1] = date_len8.Substring(4, 2);
                arrDateStr[2] = date_len8.Substring(6, 2);
                datetime = string.Join("-", arrDateStr);
                DateTime d;
                if (!DateTime.TryParse(datetime, out d)) datetime = string.Empty;
            }
            return datetime;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="content"></param>
        /// <param name="tuples"></param>
        /// <returns></returns>
        public static string MultiReplace(this string content, params object[] tuples)
        {
            if (tuples.Length == 0) return content;
            StringBuilder builder = new StringBuilder(content);
            tuples.Each(t => {
                if (t is string) builder.Replace(t.ToStringEx(), string.Empty);
                else builder.Replace(t.Val("k").ToStringEx(), t.Val("v").ToStringEx() ?? string.Empty);
            });
            return builder.ToString();
        }
        /// <summary>
        /// 判断是否为基本数据类型，包括字符串类型.
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsBaseType(this Type type)
        {
            if (type == null) return false;
            string stype = type.ToString();
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) stype = type.GetGenericArguments()[0].ToString();
            switch (stype)
            {
                case "System.String": return true;
                case "System.Boolean": return true;
                case "System.Byte": return true;
                case "System.Char": return true;
                case "System.DateTime": return true;
                case "System.Decimal": return true;
                case "System.Double": return true;
                case "System.Guid": return true;
                case "System.Int16": return true;
                case "System.Int32": return true;
                case "System.Int64": return true;
                case "System.IntPtr": return true;
                case "System.SByte": return true;
                case "System.Single": return true;
                case "System.TimeSpan": return true;
                case "System.UInt16": return true;
                case "System.UInt32": return true;
                case "System.UInt64": return true;
                case "System.UIntPtr": return true;
                case "System.Void": return true;
            }
            return false;
        }

        public static bool IsDate(this string dateString)
        {
            if (dateString != null && dateString.Trim() != string.Empty)
            {
                DateTime p;
                return DateTime.TryParse(dateString.Trim(), out p);
            }
            return false;
        }
        /// <summary>
        /// 将字符串转换成Pascal命名规范格式
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string ToPascal(this string s)
        {
            return s[0].ToString().ToUpper() + s.Substring(1, s.Length - 1);
        }

        /// <summary>
        /// 将字符串转换成Camel命名规范格式
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string ToCamel(this string s)
        {
            return s[0].ToString().ToLower() + s.Substring(1, s.Length - 1);
        }

        public static string[] Wrap<T>(this T[] arr, string left, string right)
        {
            if (arr == null) return null;
            string[] result = new string[arr.Length];
            for (var i = 0; i < arr.Length; i++) result[i] = arr[i] == null ? null : left + arr[i].ToStringEx() + right;
            return result;
        }
        #endregion

        #region nullable type extensions

        public static string GetSqlValue<T>(this Nullable<T> value) where T : struct
        {
            if (value == null || !value.HasValue)
            {
                return "NULL";
            }
            else
            {
                return value.Value.ToString();
            }
        }

        #endregion

        #region the generic interface icollection extensions.

        public static List<T> ToList<T>(this ICollection<T> collection)
        {
            List<T> list = new List<T>();
            foreach (T t in collection)
            {
                list.Add(t);
            }
            return list;
        }

        public static T[] ToArray<T>(this ICollection collection)
        {
            T[] arr = new T[collection.Count];
            int i = 0;
            foreach (object obj in collection)
            {
                arr[i++] = (T)obj;
            }
            return arr;
        }

        /// <summary>
        /// 填充满页.
        /// </summary>
        /// <typeparam name="T">model</typeparam>
        /// <param name="source">集合</param>
        /// <param name="size">每页数据量</param>
        /// <returns></returns>
        public static List<T> FillPage<T>(this List<T> source, int size) where T : class
        {
            if (source == null) source = new List<T>();
            int count = source.Count;
            for (int i = 0; i < size - count; i++) source.Add(null);
            return source;
        }
        #endregion

        #region datatable extensions

        public static IList<T> ToList<T>(this DataTable dataTable) where T : class,new()
        {
            IList<T> list = new List<T>();
            foreach (DataRow dataRow in dataTable.Rows)
            {
                T t = new T();
                PropertyInfo[] propertyInfos = t.GetType().GetProperties();
                foreach (PropertyInfo propertyInfo in propertyInfos)
                {
                    Reflector.SetPropertyValue(t, propertyInfo.Name, dataRow[propertyInfo.Name.ToLower()]);
                }
                list.Add(t);
            }
            return list;
        }

        public static void AddRange(this DataRowCollection collection, DataRow[] dataRows)
        {
            if (dataRows == null) return;
            foreach (DataRow dataRow in dataRows)
                collection.Add(dataRow);
        }

        /// <summary>
        /// 导出 HTML格式内容Excel
        /// </summary>
        /// <param name="table">数据源</param>
        /// <param name="dictExportColMappings">要导出的列的集合，key:要导出的列;value: 要导出的列的别名</param>
        /// <returns>excel的 html文本内容</returns>
        public static string ToExcel(this DataTable table, string headHtml, Dictionary<string, string> dictExportColMappings)
        {
            StringBuilder sb = new StringBuilder();

            #region 设置要导出的excel文件属性(注:<xml>与</xml>中间可有可无，可以试下去掉这些,导出文件后，看一下文件的效果)

            sb.AppendLine("<html xmlns:x=\"urn:schemas-microsoft-com:office:excel\"><head><title></title></head><body>");
            sb.AppendLine("<xml><?xml version=\"1.0\"?>");
            sb.AppendLine("<x:ExcelWorkbook>");
            sb.AppendLine("<x:ExcelWorksheets>");
            sb.AppendLine("<x:ExcelWorksheet>");
            sb.AppendFormat("<x:Name>{0}</x:Name>", table.TableName);
            sb.AppendLine("<x:WorksheetOptions>");
            sb.AppendLine("<x:Print>");
            sb.AppendLine("<x:ValidPrinterInfo/>");
            sb.AppendLine("</x:Print>");
            sb.AppendLine("</x:WorksheetOptions>");
            sb.AppendLine("</x:ExcelWorksheet>");
            sb.AppendLine("</x:ExcelWorksheets>");
            sb.AppendLine("</x:ExcelWorkbook>");
            sb.AppendLine("</xml>");

            #endregion

            //追加头部内容
            if (!string.IsNullOrEmpty(headHtml))
                sb.Append(headHtml);

            sb.AppendLine("<table>");
            //生成列名 
            sb.AppendLine("<tr style=\"font-weight: bold;\">");

            if (dictExportColMappings == null || dictExportColMappings.Count == 0)
            {
                foreach (DataColumn column in table.Columns)
                    sb.AppendFormat("<td >{0}</td>", column.ColumnName);
            }
            else
            {
                foreach (string column in dictExportColMappings.Keys)
                    sb.AppendFormat("<td >{0}</td>", dictExportColMappings[column]);
            }

            sb.AppendLine("</tr>");
            //读出所有数据
            foreach (DataRow row in table.Rows)
            {
                sb.AppendLine("<tr>");
                if (dictExportColMappings == null || dictExportColMappings.Count == 0)
                {
                    foreach (DataColumn column in table.Columns)
                    {
                        sb.AppendFormat("<td  style='vnd.ms-excel.numberformat:@'>{0}</td>", row[column].To<short>());
                    }
                }
                else
                {
                    foreach (string column in dictExportColMappings.Keys)
                    {
                        sb.AppendFormat("<td  style='vnd.ms-excel.numberformat:@'>{0}</td>", row[column].ToStringEx());
                    }
                }
                sb.AppendLine("</tr>");
            }
            sb.AppendLine("</table>");
            sb.AppendLine("</body></html>");

            return sb.ToString();
        }

        public static string ToJson(this DataTable table, params string[] fields)
        {
            if (table == null || table.Rows.Count == 0) return string.Empty;
            if (fields == null || fields.Length == 0)
            {
                fields = new string[table.Columns.Count];
                for (int i = 0; i < table.Columns.Count; i++) fields[i] = table.Columns[i].ColumnName;
            }
            StringBuilder builder = new StringBuilder();
            builder.Append("[");
            foreach (DataRow row in table.Rows)
            {
                builder.Append("{{");
                foreach (string field in fields) builder.AppendFormat("\"{0}\":\"{1}\",", field, row[field].ToStringEx());
                builder = builder.Remove(builder.Length - 1, 1);
                builder.Append("}},");
            }
            builder = builder.Remove(builder.Length - 1, 1);
            builder.Append("]");
            return builder.ToString();
        }

        /// <summary>
        /// 获取行的值，省去判断等繁琐细节。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="row"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        public static T Value<T>(this DataRow row, string field) where T : struct
        {
            if (row == null || !row.Table.Columns.Contains(field) || row[field] == DBNull.Value) return default(T);
            else if (row[field].GetType().FullName == typeof(T).FullName) return (T)row[field];
            else return (T)Convert.ChangeType(row[field], typeof(T));
        }
        /// <summary>
        /// 获取行的值，省去判断等繁琐细节。
        /// </summary>
        /// <param name="row"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        public static string Value(this DataRow row, string field)
        {
            if (row == null || !row.Table.Columns.Contains(field) || row[field] == DBNull.Value) return null;
            else return Convert.ToString(row[field]).Trim();
        }
        /// <summary>
        /// 获取行的值，省去判断等繁琐细节。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="row"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        public static Nullable<T> ValueOrNull<T>(this DataRow row, string field) where T : struct
        {
            if (row == null || !row.Table.Columns.Contains(field) || row[field] == DBNull.Value) return null;
            else if (row[field].GetType().FullName == typeof(T).FullName) return (T)row[field];
            else return (T)Convert.ChangeType(row[field], typeof(T));
        }
        /// <summary>
        /// 获取行的值，省去判断等繁琐细节。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="row"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        public static T Value<T>(this IDataReader reader, string field) where T : struct
        {
            if (reader == null) return default(T);
            else if (reader[field].GetType().FullName == typeof(T).FullName) return (T)reader[field];
            else return (T)Convert.ChangeType(reader[field], typeof(T));
        }
        /// <summary>
        /// 获取行的值，省去判断等繁琐细节。
        /// </summary>
        /// <param name="row"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        public static string Value(this IDataReader reader, string field)
        {
            if (reader == null) return null;
            return Convert.ToString(reader[field]).Trim();
        }

        #endregion

        #region generic interface IEnumerable extensions

        /// <summary>
        /// 获取枚举集合中所有元素的指定属性.
        /// </summary>
        /// <typeparam name="T">枚举集合中的元素类型</typeparam>
        /// <typeparam name="TResult">元素指定属性的类型</typeparam>
        /// <param name="ienumerable"></param>
        /// <param name="predicate">查询表达式</param>
        /// <returns></returns>
        public static TResult[] GetProperty<T, TResult>(this IEnumerable<T> ienumerable, Func<T, TResult> predicate)
        {
            return ienumerable.Select(predicate).ToArray();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ienumerable"></param>
        /// <param name="action"></param>
        public static void Each<T>(this IEnumerable<T> ienumerable, Action<T> action)
        {
            foreach (T t in ienumerable) action(t);
        }

        /// <summary>
        /// 遍历元素，并对各个元素执行action动作。仅替换for,以简化代码.
        /// 示例:  elements.Each(e=>MessageBox.Show(e.ToString()));
        /// 可能出现的异常: 
        ///                 ArgumentException
        /// </summary>
        /// <typeparam name="T">元素类型</typeparam>
        /// <param name="elements">元素集合</param>
        /// <param name="action">执行动作</param>
        /// <param name="predicate">筛选条件</param>
        /// <returns>元素集合</returns>
        public static IEnumerable<T> Each<T>(this IEnumerable<T> elements, Action<T> action, Predicate<T> predicate = null)
        {
            if (elements == null) return elements;
            foreach (T t in elements)
            {
                if (predicate == null) action(t);
                else if (predicate(t)) action(t);
            }
            return elements;
        }
        /// <summary>
        /// 遍历元素，并对各个元素执行action动作。仅替换for,以简化代码.
        /// 示例:  elements.Each(e=>MessageBox.Show(e.ToString()));
        /// 可能出现的异常: 
        ///                 ArgumentException
        /// </summary>
        /// <typeparam name="T">元素类型</typeparam>
        /// <param name="elements">元素集合</param>
        /// <param name="action">执行动作</param>
        /// <param name="predicate">筛选条件</param>
        /// <returns>元素集合</returns>
        public static IEnumerable<T> Each<T>(this IEnumerable<T> elements, Func<T, bool> action, Predicate<T> predicate = null)
        {
            if (elements == null) return elements;
            foreach (T t in elements)
            {
                bool result = true;
                if (predicate == null) result = action(t);
                else if (predicate(t)) result = action(t);
                if (result == false) break;
            }
            return elements;
        }
        /// <summary>
        /// 遍历元素，并对各个元素执行action动作。仅替换for,以简化代码.
        /// 示例:  elements.Each(e=>MessageBox.Show(e.ToString()));
        /// 可能出现的异常: 
        ///                 ArgumentException
        /// </summary>
        /// <typeparam name="T">元素类型</typeparam>
        /// <param name="elements">元素集合</param>
        /// <param name="action">执行动作</param>
        /// <param name="predicate">筛选条件</param>
        /// <returns>元素集合</returns>
        public static IEnumerable<T> Each<T>(this IEnumerable<T> elements, Action<T, int> action, Func<T, int, bool> predicate = null)
        {
            if (elements == null) return elements;
            int count = elements.Count();
            T[] arr = elements.ToArray();
            for (int i = 0; i < count; i++)
            {
                if (predicate == null) action(arr[i], i);
                else if (predicate(arr[i], i)) action(arr[i], i);
            }
            return elements;
        }
        /// <summary>
        /// 遍历元素，并对各个元素执行action动作。仅替换for,以简化代码.
        /// 示例:  elements.Each(e=>MessageBox.Show(e.ToString()));
        /// 可能出现的异常: 
        ///                 ArgumentException
        /// </summary>
        /// <typeparam name="T">元素类型</typeparam>
        /// <param name="elements">元素集合</param>
        /// <param name="action">执行动作</param>
        /// <param name="predicate">筛选条件</param>
        /// <returns>元素集合</returns>
        public static IEnumerable<T> Each<T>(this IEnumerable<T> elements, Func<T, int, bool> action, Func<T, int, bool> predicate = null)
        {
            if (elements == null) return elements;
            int count = elements.Count();
            T[] arr = elements.ToArray();
            for (int i = 0; i < count; i++)
            {
                bool result = true;
                if (predicate == null) result = action(arr[i], i);
                else if (predicate(arr[i], i)) result = action(arr[i], i);
                if (result == false) break;
            }
            return elements;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="elements"></param>
        /// <param name="comparer"></param>
        /// <returns></returns>
        public static IEnumerable<T> Distinct<T>(this IEnumerable<T> elements, Func<T, T, bool> comparer)
        {
            int count = 0;
            if (elements == null || (count = elements.Count()) == 0) return elements;
            List<T> lst = elements.ToList();
            elements.Each(e => elements.Each(s => lst.Remove(s), s => !s.Equals(e) && comparer(e, s)));
            return lst;
        }

        public static string ToExcel<T>(this IEnumerable<T> ienumerable, string sheetName, string headHtml, Dictionary<string, string> dictExportPropertyMappings)
        {
            if (ienumerable.Count() == 0) return string.Empty;
            StringBuilder sb = new StringBuilder();

            #region 设置要导出的excel文件属性(注:<xml>与</xml>中间可有可无，可以试下去掉这些,导出文件后，看一下文件的效果)

            sb.AppendLine("<html xmlns:x=\"urn:schemas-microsoft-com:office:excel\"><head><title></title></head><body>");
            sb.AppendLine("<xml><?xml version=\"1.0\"?>");
            sb.AppendLine("<x:ExcelWorkbook>");
            sb.AppendLine("<x:ExcelWorksheets>");
            sb.AppendLine("<x:ExcelWorksheet>");
            sb.AppendFormat("<x:Name>{0}</x:Name>", sheetName);
            sb.AppendLine("<x:WorksheetOptions>");
            sb.AppendLine("<x:Print>");
            sb.AppendLine("<x:ValidPrinterInfo/>");
            sb.AppendLine("</x:Print>");
            sb.AppendLine("</x:WorksheetOptions>");
            sb.AppendLine("</x:ExcelWorksheet>");
            sb.AppendLine("</x:ExcelWorksheets>");
            sb.AppendLine("</x:ExcelWorkbook>");
            sb.AppendLine("</xml>");

            #endregion
            //追加头部内容
            sb.AppendFormat("<center><h2>{0}</h2></center>", sheetName);
            if (!string.IsNullOrEmpty(headHtml))
                sb.Append(headHtml);

            sb.AppendLine("<table>");

            //生成列名 
            sb.AppendLine("<tr style=\"font-weight: bold;\">");
            PropertyInfo[] propertyies = ienumerable.First().GetType().GetProperties().Where(p => p.PropertyType.IsBaseType()).ToArray();
            if (dictExportPropertyMappings == null || dictExportPropertyMappings.Count == 0)
                foreach (PropertyInfo property in propertyies)
                    sb.AppendFormat("<td >{0}</td>", property.Name);
            else
                foreach (string column in dictExportPropertyMappings.Keys)
                    if (propertyies.Select(p => p.Name).Contains(column))
                        sb.AppendFormat("<td >{0}</td>", dictExportPropertyMappings[column]);

            sb.AppendLine("</tr>");

            //读出所有数据
            foreach (T t in ienumerable)
            {
                sb.AppendLine("<tr>");
                if (dictExportPropertyMappings == null || dictExportPropertyMappings.Count == 0)
                    foreach (PropertyInfo property in propertyies)
                        sb.AppendFormat("<td  style='vnd.ms-excel.numberformat:@'>{0}</td>", property.GetValue(t, null));
                else
                {
                    foreach (string column in dictExportPropertyMappings.Keys)
                    {
                        PropertyInfo propertyInfo = propertyies.Where(p => p.Name == column).FirstOrDefault();
                        if (propertyInfo != null)
                            sb.AppendFormat("<td  style='vnd.ms-excel.numberformat:@'>{0}</td>", propertyInfo.GetValue(t, null));
                    }
                }
                sb.AppendLine("</tr>");
            }

            sb.AppendLine("</table>");
            sb.AppendLine("</body></html>");

            return sb.ToString();
        }

        public static string ToJson<T>(this IEnumerable<T> ienumerable, IDictionary<string, Func<T, object>> getProperties)
        {
            if (ienumerable == null || ienumerable.Count() == 0 || getProperties == null || getProperties.Count == 0) return string.Empty;
            StringBuilder builder = new StringBuilder();
            builder.Append("[");
            foreach (T t in ienumerable)
            {
                builder.Append("{{");
                foreach (string key in getProperties.Keys) builder.AppendFormat("\"{0}\":\"{1}\",", key, getProperties[key](t).ToStringEx());
                builder = builder.Remove(builder.Length - 1, 1);
                builder.Append("}},");
            }
            builder = builder.Remove(builder.Length - 1, 1);
            builder.Append("]");
            return builder.ToString();
        }

        /// <summary>
        /// 将泛型集合转换成DataTable
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="elements"></param>
        /// <param name="tableName">表名</param>
        /// <returns></returns>
        public static DataTable ToTable<T>(this IEnumerable<T> elements, string tableName = null) where T : class
        {
            if (elements == null) return null;
            DataTable result = new DataTable();
            Type type = typeof(T);
            if (tableName != null && tableName.Trim() != string.Empty) result.TableName = tableName;
            else result.TableName = type.Name;

            MemberInfo[] properties = type.GetProperties();
            MemberInfo[] fields = type.GetFields();
            IEnumerable<MemberInfo> members = properties.Concat(fields);
            List<MemberInfo> listMemberColumns = new List<MemberInfo>();
            foreach (MemberInfo member in members)
            {
                Type ptype = typeof(System.Object);
                if (member is PropertyInfo) ptype = (member as PropertyInfo).PropertyType;
                else ptype = (member as FieldInfo).FieldType;

                bool isString = ptype.ToString() == "System.String";
                bool nullable = isString;
                string caption = string.Empty;
                //datetime
                if (!isString && (ptype.IsClass || ptype.IsInterface || ptype.IsByRef) && !ptype.IsPrimitive)
                {
                    continue;//非基本类型，则跳过。因为Ado.net不支持。
                }
                else if (ptype.IsGenericType && ptype.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    ptype = ptype.GetGenericArguments()[0];
                    if (!isString && (ptype.IsClass || ptype.IsInterface || ptype.IsByRef) && !ptype.IsPrimitive) continue;//非基本类型，则跳过。因为Ado.net不支持。
                    nullable = true;
                }
                //Low efficiency code.
                //object[] captions = property.GetCustomAttributes(typeof(DisplayNameAttribute), false);
                //if (captions != null && captions.Length > 0) caption = (captions[0] as DisplayNameAttribute).DisplayName;
                result.Columns.Add(new DataColumn { ColumnName = member.Name, DataType = ptype, AllowDBNull = nullable, Caption = member.Name });
                listMemberColumns.Add(member);
            }

            foreach (T e in elements)
            {
                object[] values = new object[result.Columns.Count];
                int index = 0;
                foreach (MemberInfo member in listMemberColumns)
                {
                    if (member is PropertyInfo) values[index++] = (member as PropertyInfo).GetValue(e, null);
                    else values[index++] = (member as FieldInfo).GetValue(e);
                }
                result.LoadDataRow(values, true);
            }
            return result;
        }

        #endregion

        #region other extensions

        public static string ToHtml(this System.Drawing.Color color)
        {
            return System.Drawing.ColorTranslator.ToHtml(color);
        }

        /// <summary>
        /// 判断是否为基本类型，包字符串类型
        /// </summary>
        /// <param name="property"></param>
        /// <returns></returns>
        public static bool IsBaseType(this System.Reflection.PropertyInfo property)
        {
            return property.PropertyType.IsBaseType();
        }
        /// <summary>
        /// 图片转为2进制
        /// </summary>
        /// <param name="image"></param>
        /// <returns></returns>
        public static byte[] ToBytes(System.Drawing.Image image)
        {
            System.IO.MemoryStream imageStream = new System.IO.MemoryStream();
            image.Save(imageStream, image.RawFormat);
            return imageStream.ToArray();
        }
        //将byte[]转换为Image
        public static System.Drawing.Image ToImage(this byte[] bytes)
        {
            if (bytes == null) return null;
            System.IO.MemoryStream ms = new System.IO.MemoryStream(bytes, 0, bytes.Length);
            return System.Drawing.Image.FromStream(ms);
        }


        #endregion
    }
}
